
#include "MainFrame.h"

MainFrame::MainFrame(void)
	: loopTime(1000), world(new World(39, 39))
{
    MessageArray::Instance()->addSubscriber(this);
    MessageArray::Instance()->addSubscriber(&mainMenu);
    MessageArray::Instance()->addSubscriber(&demoMenu);
    MessageArray::Instance()->addSubscriber(&aboutDialog);
    MessageArray::Instance()->postMessage(APP_START);
}

MainFrame::~MainFrame(void)
{
}

void MainFrame::run()
{
    keyboardListener();
}

void MainFrame::keyboardListener()
{
    char key;
    std::cin >> key;
    MessageArray::Instance()->postMessage(static_cast<U_MESSAGE>(key));
}

bool MainFrame::fire()
{
    U_MESSAGE msg(MessageArray::Instance()->getMessage());
    switch (msg)
    {
    case APP_START:
        MessageArray::Instance()->postMessage(SHOW_MAINMENU);
        return true;
    case QUIT:
        //frameQuit();
        exit(0);
        break;
    case SHOW_DEMO_ONE:
        showDemoOne();
        return true;
    case SHOW_DEMO_CONVEYER_BELT:
        showConveyerBelt();
        return true;
    case SHOW_DEMO_GUN:
        showGun();
        return true;
    case SHOW_DEMO_STRLINE:
        showStraightLine();
        return true;
    case SHOW_DEMO_DSTRLINE:
        showDoubleStraightLine();
        return true;
    case SHOW_DEMO_RECTANGLE:
        showRectangle();
        return true;
    case CONFIG_LOOP_TIME:
        configLoopTime();
        return true;
    case CONFIG_WORLD_SIZE:
        configWorldSize();
        return true;
    case CONFIG_LIFE:
        configLife();
        return true;
    case RUN_CONFIGWORLD:
        runConfigWorld();
        return true;
    case RUN_RANDOMWORLD:
        runRandomWorld();
        return true;
    case RUN_RESUMELAST:
        resumeLast();
        return true;
    default:
        break;
    }
    return false;
}

void MainFrame::showConveyerBelt()
{
    world.reset(new World(39, 39));

    world->setSquare(4,	3, 1);
    world->setSquare(4,	4, 1);
    world->setSquare(5,	3, 1);
    world->setSquare(5,	5, 1);
    world->setSquare(7,	5, 1);
    world->setSquare(7,	7, 1);
    world->setSquare(9,	7, 1);
    world->setSquare(9,	9, 1);
    world->setSquare(11, 9, 1);
    world->setSquare(11, 11, 1);
    world->setSquare(13, 11, 1);
    world->setSquare(13, 13, 1);
    world->setSquare(15, 13, 1);
    world->setSquare(15, 15, 1);
    world->setSquare(16, 14, 1);
    world->setSquare(16, 15, 1);

    for (size_t loop = 0; loop != loopTime; ++loop)
    {
        world->show();
        Sleep(100);
        world->refresh();
        system("cls");
    }
}

void MainFrame::showDemoOne()
{
    world.reset(new World(39, 39));

    world->setSquare(1 + 10, 9 + 10, 1);
    world->setSquare(2 + 10, 8 + 10, 1);
    world->setSquare(2 + 10, 9 + 10, 1);
    world->setSquare(2 + 10, 10 + 10, 1);
    world->setSquare(3 + 10, 8 + 10, 1);
    world->setSquare(3 + 10, 10 + 10, 1);
    world->setSquare(3 + 10, 11 + 10, 1);

    showWorld();
}

void MainFrame::showGun()
{
    world.reset(new World(39, 39));

    world->setSquare(0, 15, 1);
    world->setSquare(1, 14, 1);
    world->setSquare(1, 15, 1);
    world->setSquare(1, 16, 1);
    world->setSquare(1, 17, 1);
    world->setSquare(2, 13, 1);
    world->setSquare(2, 14, 1);
    world->setSquare(2, 16, 1);
    world->setSquare(2, 25, 1);
    world->setSquare(2, 26, 1);
    world->setSquare(3, 2, 1);
    world->setSquare(3, 3, 1);
    world->setSquare(3, 12, 1);
    world->setSquare(3, 13, 1);
    world->setSquare(3, 14, 1);
    world->setSquare(3, 16, 1);
    world->setSquare(3, 18, 1);
    world->setSquare(3, 25, 1);
    world->setSquare(3, 28, 1);
    world->setSquare(4, 2, 1);
    world->setSquare(4, 13, 1);
    world->setSquare(4, 14, 1);
    world->setSquare(4, 16, 1);
    world->setSquare(4, 29, 1);
    world->setSquare(5, 14, 1);
    world->setSquare(5, 15, 1);
    world->setSquare(5, 16, 1);
    world->setSquare(5, 17, 1);
    world->setSquare(5, 29, 1);
    world->setSquare(5, 36, 1);
    world->setSquare(5, 37, 1);
    world->setSquare(6, 15, 1);
    world->setSquare(6, 29, 1);
    world->setSquare(6, 37, 1);
    world->setSquare(7, 25, 1);
    world->setSquare(7, 28, 1);
    world->setSquare(8, 25, 1);
    world->setSquare(8, 26, 1);

    showWorld();
}

void MainFrame::showWorld() const
{    
    using std::cout;
    using std::cin;
    using std::endl;
    using std::ends;

    for (size_t loop = 0; loop != loopTime; ++loop)
    {
        system("cls");
        world->show();
        world->refresh();
        Sleep(10);
    }

    cout << "Display over." 
         << ends
         << "3 seconds to main menu..." 
         << endl;
    Sleep(3000);
    MessageArray::Instance()->postMessage(SHOW_MAINMENU);
}

void MainFrame::showStraightLine()
{
    world.reset(new World(39, 39));
    for (size_t i = 7; i != world->getColumn() - 7; ++i)
        world->setSquare(world->getRow() / 2, i, 1);
    showWorld();
}

void MainFrame::showDoubleStraightLine()
{
    world.reset(new World(39, 39));
    for (size_t i = 7; i != world->getColumn() - 7; ++i)
    {
        world->setSquare(world->getRow() / 2 + 4, i, 1);
        world->setSquare(world->getRow() / 2 - 4, i, 1);
    }
    showWorld();
}

void MainFrame::showRectangle()
{
    world.reset(new World(39, 39));
    for (size_t i = 7; i != world->getColumn() - 7; ++i)
    {
        world->setSquare(world->getRow() / 2 + 4, i, 1);
        world->setSquare(world->getRow() / 2 - 4, i, 1);
    }
    for (size_t i = world->getRow() / 2 - 4; i <= world->getRow() / 2 + 4; ++i)
    {
        world->setSquare(i, 7, 1);
        world->setSquare(i, world->getColumn() - 7, 1);
    }
    showWorld();
}

void MainFrame::configLoopTime()
{
    using std::cout;
    using std::cin;
    using std::endl;
    using std::ends;

    system("cls");

    cout << "Current it's "
         << loopTime
         << ".\nEnter how many times you want it to run: "
         << ends;
    int n;
    cin >> n;
    while (n <= 0)
    {
        cout << "Loop time should be positive. Please try again." << endl;
        cin >> n;
    }
    loopTime = n;

    MessageArray::Instance()->postMessage(SHOW_MAINMENU);
}

void MainFrame::configWorldSize()
{
    using std::cout;
    using std::cin;
    using std::endl;
    using std::ends;

    system("cls");
    long r, c;
    //Enter number of rows.
    cout << "Enter world size...\n"
         << "Number of rows should be no more than 39 for best apperance...\n"
         << "Number of rows: "
         << ends;
    cin >> r;
    while (r <= 0)
    {
        cout << "Number of rows should be positive. Please try again." << endl;
        cin >> r;
    }

    //Enter number of columns.
    cout<< "Number of columns: "
        << ends;
    cin >> c;
    while (c <= 0)
    {
        cout << "Number of columns should be positive. Please try again." << endl;
        cin >> c;
    }

    world.reset(new World(r, c));

    MessageArray::Instance()->postMessage(SHOW_MAINMENU);
}

void MainFrame::configLife()
{
    using std::cout;
    using std::cin;
    using std::endl;
    using std::ends;

    world->clear();
    system("cls");

    cout << "Enter life position, in the form of (1, row, column),\n"
         << "e.g. 1 1 1\n"
         << "No need for non-life position.\n"
         << "Enter (-1) to finish.\n"
         << "The boundry is Row: "
         << world->getRow()
         << ", Column: "
         << world->getColumn()
         << endl;

    size_t r, c;
    int v;

    cin >> v;
    while (v != -1)
    {
        cin >> r >> c;
        if (r > world->getRow() || c > world->getColumn())
            cout << "Exceed the boundry." << endl;
        else
            world->setSquare(r, c, (v > 0 ? 1 : 0));
        cin >> v;
    }

    system("cls");
    world->show();
    cout << "3 seconds to main menu..." << endl;
    Sleep(3000);

    MessageArray::Instance()->postMessage(SHOW_MAINMENU);
}

void MainFrame::runConfigWorld()
{
    showWorld();
}

void MainFrame::runRandomWorld()
{
    world->randomize();
    showWorld();
}

void MainFrame::resumeLast()
{
    showWorld();
}
